package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hmdp.common.ErrorCode;
import com.hmdp.constant.RedisConstants;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.Follow;
import com.hmdp.entity.User;
import com.hmdp.exception.BusinessException;
import com.hmdp.mapper.FollowMapper;
import com.hmdp.service.IFollowService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IUserService;
import com.hmdp.utils.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IUserService userService;

    @Override
    public Result concernUser(Long concernUserId, Boolean isConcern) {
        if (concernUserId == null || isConcern == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "传入的参数不能为空");
        }
        // 1. 获取当前登录用户
        UserDTO userDTO = UserHolder.getUser();
        if (userDTO == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "您还没有登录无法进行关注的相关操作");
        }
        Long currentLoginUserID = userDTO.getId();
        if (currentLoginUserID == null || currentLoginUserID < 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前用户id错误");
        }
        // 2. 判断当前用户的操作是关注还是取关
        if (BooleanUtil.isTrue(isConcern)) {
            // 2.操作是 关注，就新增一条数据
            Follow follow = new Follow();
            // 设置当前用户的id
            follow.setUserId(currentLoginUserID);
            // 设置当前用户 要 关注的用户的id
            follow.setFollowUserId(concernUserId);
            // 插入数据库
            boolean saveResult = this.save(follow);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "关注失败");
            }
            // 3. 插入数据成功后，还要将 关注的用户的id存入redis
            Long addRedisResult = stringRedisTemplate.opsForSet().add("follow:common:" + currentLoginUserID, concernUserId.toString());
            if (addRedisResult == null || addRedisResult.intValue() < 0) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "redis关注数添加未成功");
            }
        } else {
            // 4. 操作是 取关，就删除数据
            boolean removeResult = this.remove(new QueryWrapper<Follow>().eq("user_id", currentLoginUserID).eq("follow_user_id", concernUserId));
            if (!removeResult) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "取关失败");
            }
            // 5. 删除完数据库的数据后，还要删除redis中的数据
            Long removeRedis = stringRedisTemplate.opsForSet().remove("follow:common:" + currentLoginUserID, concernUserId.toString());
            if (removeRedis == null || removeRedis.intValue() < 0) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "redis关注数删除未成功");
            }
        }
        return Result.ok();
    }

    @Override
    public Result isConcernOrNot(Long userId) {
        if (userId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "传入的参数不能为空");
        }
        // 1. 获取当前登录的用户
        UserDTO userDTO = UserHolder.getUser();
        if (userDTO == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "您还没有登录无法进行关注的相关操作");
        }
        Long currentLoginUserID = userDTO.getId();
        if (currentLoginUserID == null || currentLoginUserID < 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前用户id错误");
        }
        // 2. 根据当前用户id和传入的是否关注的用户id，查询数据库
        int count = this.count(new QueryWrapper<Follow>().eq("user_id", currentLoginUserID).eq("follow_user_id", userId));
        return Result.ok(count > 0);
    }

    @Override
    public Result commonConcern(Long concernUserId) {
        if (concernUserId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "传入的参数不能为空");
        }
        // 1. 获取当前登录用户的 id
        UserDTO userDTO = UserHolder.getUser();
        if (userDTO == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "您还没有登录无法进行关注的相关操作");
        }
        Long currentLoginUserID = userDTO.getId();
        if (currentLoginUserID == null || currentLoginUserID < 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前用户id错误");
        }
        // 2. 根据redis中 set数据结构的特性。 查出当前登录用户和关注用户两个set的公共value，这个value就是两人的公共关注
        Set<String> intersect = stringRedisTemplate.opsForSet().intersect("follow:common:" + currentLoginUserID, "follow:common:" + concernUserId);
        if (intersect == null || intersect.isEmpty()) {
            // 等于空，说明没有共同关注
            return Result.ok(Collections.emptyList());
        }        // 3. 将得到的 公共关注的id转型
        List<Long> commonUserIdList = intersect.stream().map(Long::valueOf).collect(Collectors.toList());
        // 4. 再 根据 转型后的id，查询用户信息
        List<User> users = userService.listByIds(commonUserIdList);
        List<UserDTO> userDTOList = users.stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());

        return Result.ok(userDTOList);
    }
}
